package org.jupiter.blog.authentic.handler;

import org.jupiter.blog.authentic.constant.AuthenticConstant;
import org.jupiter.blog.authentic.utils.AuthenticUtils;
import org.jupiter.blog.common.constant.SymbolConstant;
import org.jupiter.blog.redis.component.SpringRedisRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authorization.AuthorizationDecision;
import org.springframework.security.authorization.AuthorizationManager;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.web.access.intercept.RequestAuthorizationContext;
import org.springframework.stereotype.Component;
import org.springframework.web.util.pattern.PathPattern;
import org.springframework.web.util.pattern.PathPatternParser;
import org.springframework.http.server.PathContainer;

import java.util.Map;
import java.util.Set;
import java.util.function.Supplier;
import java.util.stream.Collectors;

@Component
public class RedisAuthorizationManager implements AuthorizationManager<RequestAuthorizationContext> {

	@Autowired
	private SpringRedisRepository redisRepository;

	private static final PathPatternParser PATH_PARSER = new PathPatternParser();

	@Override
	public AuthorizationDecision check(Supplier<Authentication> authentication, RequestAuthorizationContext context) {
		String rawPath = normalizePath(context.getRequest().getRequestURI());
		String method = context.getRequest().getMethod();
		Authentication auth = authentication.get();
		String redisKey = AuthenticUtils.getRedisKey(AuthenticConstant.ALL_URL_SET_PREFIX, method);
		// 1) 获取该方法下的全部 URL 模式集合
		Set<String> patterns = redisRepository.setMembers(redisKey);

		if (patterns == null || patterns.isEmpty()){
			return new AuthorizationDecision(true);
		}

		// 2) 选择匹配的最具体模式
		PathContainer path = PathContainer.parsePath(rawPath);
		String matchedPattern = patterns.stream()
				.filter(p -> PATH_PARSER.parse(p).matches(path))
				.sorted((a, b) -> PathPattern.SPECIFICITY_COMPARATOR
						.compare(PATH_PARSER.parse(a), PATH_PARSER.parse(b)))
				.reduce((first, second) -> second) // 取最具体（排序后最后一个）
				.orElse(null);

		if (matchedPattern == null){
			return new AuthorizationDecision(true);
		}

		// 3) 获取该URL所需的权限点集合
		String urlPermissionKey = AuthenticUtils.getRedisKey(AuthenticConstant.URL_PERMISSION_PREFIX, method, SymbolConstant.COLON, matchedPattern);
		Set<String> requiredPermissions = redisRepository.setMembers(urlPermissionKey);

		if (requiredPermissions.isEmpty()){
			return new AuthorizationDecision(true);
		}

		// 4) 获取用户权限集合key
		String userPermissionKey = AuthenticUtils.getRedisKey(AuthenticConstant.PERMISSIONS_USER_PREFIX, auth.getName());

		// 5) 在Redis中直接计算两个Set的交集
		Set<String> intersection = redisRepository.setIntersect(urlPermissionKey, userPermissionKey);
		boolean granted = !intersection.isEmpty();

		return new AuthorizationDecision(granted);
	}

	private String normalizePath(String raw) {
		if (raw == null || raw.isEmpty())
			return "/";
		int q = raw.indexOf('?');
		String path = q >= 0 ? raw.substring(0, q) : raw;
		if (path.length() > 1 && path.endsWith("/")){
			return path.substring(0, path.length() - 1);
		}
		return path;
	}
}
